package hxtc.events;

import jstm.Host;
/**
 * ...
 * @author Cref
 */

class Use0 {
	public static inline function doBefore<R>(a:Void->R,b:Void->R):Void {
		//ClosureEventDispatcher.getDispatcher(a).addBeforeListener(
	}
	public static inline function doAfter<R>(a:Void->R,b:R->Void):Void {
		
	}
}

class Use1 {
	public static inline function doBefore<A0,R>(a:A0->R,b:A0->R):Void {
		
	}
	public static inline function doAfter<A0,R>(a:A0->R,b:R->Void):Void {
		
	}
}

class ClosureEventDispatcher {
	public static function getDispatcher(closure:Dynamic):ClosureEventDispatcher {
		var c:Closure = cast closure;
		//untyped alert(Tools.getInstanceId(c.scope)+c._name);
		var currentFunction:Dynamic = cast c.scope[cast c._name];
		return currentFunction._eventTarget == null
			?new ClosureEventDispatcher(c)
			:currentFunction._eventTarget
		;
	}
	var evtId:String;
	var aEvent:org.w3c.dom.events.Event;
	function new(c:Closure):Void {
		evtId = Tools.getInstanceId(c.scope) + '.' + c._name;
		Tools.patch(c, fnPatch);
	}
	
	function createEvent(type:String):Dynamic {
		var event = Host.window.document.createEvent('Event');
		event.initEvent(type + evtId, false, true);
		return event;
	}
	
	function fnPatch(f:Dynamic) {
		var t = this, r:Dynamic = function() {
			var bEvent:Before = t.createEvent('b');
			bEvent.args = ES5.arguments;
			//bEvent.closure = t;
			if (!Host.window.dispatchEvent(cast bEvent)) return;
			var aEvent:After = t.createEvent('a');
			aEvent.returnValue = f.apply(null, ES5.arguments);
			Host.window.dispatchEvent(cast aEvent);
			return aEvent.returnValue;
		};
		r._eventTarget = t;
		return r;
	}
	
	public function addBeforeListener(listener:Before->Void):ClosureEventDispatcher {
		Host.window.addEventListener('b' + evtId, cast listener, false);
		return this;
	}
	
	public function removeBeforeListener(listener:Before->Void):ClosureEventDispatcher {
		Host.window.removeEventListener('b' + evtId, listener, false);
		return this;
	}
	
	public function addAfterListener(listener:After->Void):ClosureEventDispatcher {
		Host.window.addEventListener('a' + evtId, cast listener, false);
		return this;
	}
	
	public function removeAfterListener(listener:After->Void):ClosureEventDispatcher {
		Host.window.removeEventListener('a' + evtId, listener, false);
		return this;
	}
}

typedef Closure = { scope:Dynamic, method:Function<Dynamic,Dynamic,Dynamic>, _name:String }

typedef Before = { closure:Closure, args:Arguments<Dynamic>, preventDefault:Void->Void, stopPropagation:Void->Void }
//TODO: add type:
//typedef After<R>={closure:Closure,returnValue:R,stopPropagation:Void->Void}
typedef After={closure:Closure,returnValue:Dynamic,stopPropagation:Void->Void}